package com.example.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.geotools.data.DataUtilities;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.geometry.jts.JTSFactoryFinder;

import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author angzhijin
 * @description
 * @create 2022-11-20 18:07
 */
@Slf4j
public class GeoUtils {

    /**
     * 地理数据类型
     * 点、线、面、几何集合
     */
    private static final String[] GEO_TYPE = new String[]{"Geometry", "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection"};

    private final static GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);

    // WKT 读取类
    private final static WKTReader reader = new WKTReader(geometryFactory);
    // GeoJSON 转换器
    private final static GeometryJSON geometryJson = new GeometryJSON(2);
    private final static FeatureJSON featureJson = new FeatureJSON(geometryJson);

    /**
     * 获取几何类型
     * @param wkt WKT格式字符串
     * @return 几何类型
     */
    public static String getGeoTypeFromWKT(String wkt){
        String type = null;
        if (Strings.isNotEmpty(wkt)) {
            try {
                Geometry read = reader.read(wkt);
                type = read.getGeometryType();
            }catch (Exception e) {
                log.error("invalid WKT String：", e);
                e.printStackTrace();
            }
        }
        return type;
    }

    /**
     * 点坐标值转换为WKT格式
     * @param x x坐标值
     * @param y y坐标值
     * @return 点类型WKT
     */
    public static String Point2WKT(int x, int y){
        return "POINT(" + x + " " + y + ")";
    }

    /**
     * 线坐标值转换为WKT格式
     * @param x1 起点x坐标值
     * @param y1 起点y坐标值
     * @param x2 终点x坐标值
     * @param y2 终点y坐标值
     * @return 线类型WKT
     */
    public static String Line2WKT(int x1, int y1, int x2, int y2){
        return "LINESTRING("+x1+ " "+y1 + ","+x2+" "+y2 +")";
    }

    /**
     * WKT格式文本对象转换为GeoJSON
     * @param wkt WKT格式文本
     * @return GeoJson对象
     */
    public static String wktToJson(String wkt) {
        String json = null;
        try {
            Geometry geometry = reader.read(wkt);
            json = geometryJson.toString(geometry);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return json;
    }

    /**
     * Geometry对象转换为GeoJSON
     * @param geometry 空间几何对象
     * @return GeoJSON对象
     */
    public static String geoToJson(Geometry geometry) {
        return geometryJson.toString(geometry);
    }

    /**
     * Feature转换为GeoJSON
     * @param feature Feature要素对象
     * @return GeoJSON对象
     */
    public static String featureToJson(SimpleFeature feature){
        String json = null;
        try{
            json = featureJson.toString(feature);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return json;
    }

    /**
     * Feature集合转换为GeoJSON
     * @param features FeatureCollection对象
     * @return GeoJSON文本
     */
    public static String featureCollectionToJson(SimpleFeatureCollection features){
        String json = null;
        try{
            json = featureJson.toString(features);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return json;
    }

    /**
     * 1*2二维坐标数组转换为点对象
     * point(Array) -> coordinate -> Point(Geometry)
     * @param x x坐标
     * @param y y坐标
     * @return Point(Geometry) 点对象
     */
    public static Point createPoint(double x, double y) {
        return geometryFactory.createPoint(new Coordinate(x, y));
    }


    /**
     * n*2二维坐标数组转换为点集对象
     * points(Array[Array]) -> Point[] -> MultiPoint(Geometry)
     * @param pointArrays n*2数组
     * @return MultiPoint(Geometry) 点集对象
     */
    public static MultiPoint createMultiPoint(double[][] pointArrays){
        int size = pointArrays.length;
        Point[] points = new Point[size];
        for (int i = 0; i < size; i++) {
            points[i] = createPoint(pointArrays[i][0], pointArrays[i][1]);
        }
        return geometryFactory.createMultiPoint(points);
    }

    /**
     * 点数组转换为点集
     * Point[] -> Geometry
     * @param points 点数组
     * @return 点集对象
     */
    public static MultiPoint pointsToMultiPoint(Point[] points){
        return new MultiPoint(points, geometryFactory);
    }

    public static void main(String[] args) throws IOException {
        /**
         * Builder 创建要素
         */
        // A. Builder方式创建FeatureType
        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        //set the name
        typeBuilder.setName( "Flag" );
        //add some properties
        typeBuilder.add( "name", String.class );
        typeBuilder.add( "classification", Integer.class );
        typeBuilder.add( "height", Double.class );
        //add a geometry property
        typeBuilder.setCRS( DefaultGeographicCRS.WGS84 );
        typeBuilder.add( "location", Point.class );
        //build the type
        SimpleFeatureType featureType = typeBuilder.buildFeatureType();

        // B. Builder方式创建Feature
        //create the builder
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
        //add the values
        builder.add( "Canada" );
        builder.add( 1 );
        builder.add( 20.5 );
        builder.add( geometryFactory.createPoint(new Coordinate(-124, 52)) );
        //build the feature with provided ID
        SimpleFeature feature = builder.buildFeature( "fid.0" );
        System.out.println(featureJson.toString(feature));


        List<SimpleFeature> features = new ArrayList<>();
        features.add(feature);
        // C. Construct方式创建FeatureCollection(复用List, 动态)
        SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features);
        System.out.println("generated by new ListFeatureCollection: " + featureJson.toString(collection));
        // D. 工具类方式创建FeatureCollection(复制为Map, 静态)
        SimpleFeatureCollection collection1 = DataUtilities.collection(features); // 使用DataUtilities
        System.out.println("generated by DataUtilities: " + featureJson.toString(collection1));


        /**
         * 约定文本格式 创建要素
         */
        SimpleFeatureType simpleType;
        try {
            simpleType = DataUtilities.createType("Candiante", "location:Point,name:\"\",size:0.0,weight:0.0");
            System.out.println(DataUtilities.encodeType(simpleType));

        } catch (SchemaException e) {
            throw new RuntimeException(e);
        }
        SimpleFeatureBuilder builder2 = new SimpleFeatureBuilder(simpleType);
        builder2.add(geometryFactory.createPoint(new Coordinate(5,5)));
        builder2.add("abc");
        builder2.add(6);
        builder2.add(50);
        SimpleFeature feature2 = builder2.buildFeature("point.2");
        System.out.println(featureJson.toString(feature2));

        SimpleFeature feature3 = DataUtilities.createFeature(simpleType, "POINT(6 6)|point2|7.7|8.8");
        System.out.println(featureJson.toString(feature3));
        System.out.println(DataUtilities.encodeFeature(feature3));


    }
}
